home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xrubik / Rubik2d.c < prev    next >
C/C++ Source or Header  |  1996-03-26  |  18KB  |  533 lines

  1. /*
  2. # X-BASED RUBIK'S CUBE(tm)
  3. #
  4. #  Rubik2d.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Rubik2d */
  27.  
  28. #include <stdio.h>
  29. #include <X11/IntrinsicP.h>
  30. #include <X11/Intrinsic.h>
  31. #include <X11/StringDefs.h>
  32. #include <X11/CoreP.h>
  33. #include "RubikP.h"
  34. #include "Rubik2dP.h"
  35.  
  36. static void InitializeRubik2D();
  37. static void ResizeRubik2D();
  38. static void ExposeRubik2D();
  39. static Boolean SetValuesRubik2D();
  40. static void MoveRubik2DTop();
  41. static void MoveRubik2DLeft();
  42. static void MoveRubik2DRight();
  43. static void MoveRubik2DBottom();
  44. static void ResizePolyhedrons();
  45. static void DrawFrame();
  46. static void DrawOrientLine();
  47.  
  48. static char defaultTranslationsRubik2D[] =
  49.   "<KeyPress>q: Quit()\n\
  50.    Ctrl<KeyPress>C: Quit()\n\
  51.    <KeyPress>KP_Divide: MoveCcw()\n\
  52.    <KeyPress>Up: MoveTop()\n\
  53.    <KeyPress>KP_8: MoveTop()\n\
  54.    <KeyPress>R8: MoveTop()\n\
  55.    <KeyPress>Left: MoveLeft()\n\
  56.    <KeyPress>KP_4: MoveLeft()\n\
  57.    <KeyPress>R10: MoveLeft()\n\
  58.    <KeyPress>Begin: MoveCw()\n\
  59.    <KeyPress>KP_5: MoveCw()\n\
  60.    <KeyPress>R11: MoveCw()\n\
  61.    <KeyPress>Right: MoveRight()\n\
  62.    <KeyPress>KP_6: MoveRight()\n\
  63.    <KeyPress>R12: MoveRight()\n\
  64.    <KeyPress>Down: MoveBottom()\n\
  65.    <KeyPress>KP_2: MoveBottom()\n\
  66.    <KeyPress>R14: MoveBottom()\n\
  67.    <Btn1Down>: Select()\n\
  68.    <Btn1Up>: Release()\n\
  69.    <KeyPress>p: Practice()\n\
  70.    <Btn2Down>(2+): Practice()\n\
  71.    <Btn2Down>: PracticeMaybe()\n\
  72.    <KeyPress>r: Randomize()\n\
  73.    <Btn3Down>(2+): Randomize()\n\
  74.    <Btn3Down>: RandomizeMaybe()\n\
  75.    <KeyPress>g: Get()\n\
  76.    <KeyPress>w: Write()\n\
  77.    <KeyPress>u: Undo()\n\
  78.    <KeyPress>s: Solve()\n\
  79.    <KeyPress>i: Increment()\n\
  80.    <KeyPress>d: Decrement()\n\
  81.    <KeyPress>o: Orientize()";
  82.  
  83. static XtActionsRec actionsListRubik2D[] =
  84. {
  85.   {"Quit", (XtActionProc) QuitRubik},
  86.   {"MoveCcw", (XtActionProc) MoveRubikCcw},
  87.   {"MoveTop", (XtActionProc) MoveRubik2DTop},
  88.   {"MoveLeft", (XtActionProc) MoveRubik2DLeft},
  89.   {"MoveCw", (XtActionProc) MoveRubikCw},
  90.   {"MoveRight", (XtActionProc) MoveRubik2DRight},
  91.   {"MoveBottom", (XtActionProc) MoveRubik2DBottom},
  92.   {"Select", (XtActionProc) SelectRubik},
  93.   {"Release", (XtActionProc) ReleaseRubik},
  94.   {"Practice", (XtActionProc) PracticeRubik},
  95.   {"PracticeMaybe", (XtActionProc) PracticeRubikMaybe},
  96.   {"Randomize", (XtActionProc) RandomizeRubik},
  97.   {"RandomizeMaybe", (XtActionProc) RandomizeRubikMaybe},
  98.   {"Get", (XtActionProc) GetRubik},
  99.   {"Write", (XtActionProc) WriteRubik},
  100.   {"Undo", (XtActionProc) UndoRubik},
  101.   {"Solve", (XtActionProc) SolveRubik},
  102.   {"Increment", (XtActionProc) IncrementRubik},
  103.   {"Decrement", (XtActionProc) DecrementRubik},
  104.   {"Orientize", (XtActionProc) OrientizeRubik}
  105. };
  106.  
  107. static XtResource resourcesRubik2D[] =
  108. {
  109.   {XtNfaceColor0, XtCLabel, XtRString, sizeof(String),
  110.    XtOffset(RubikWidget, rubik.faceName[0]), XtRString, "Red"},
  111.   {XtNfaceColor1, XtCLabel, XtRString, sizeof(String),
  112.    XtOffset(RubikWidget, rubik.faceName[1]), XtRString, "Yellow"},
  113.   {XtNfaceColor2, XtCLabel, XtRString, sizeof(String),
  114.    XtOffset(RubikWidget, rubik.faceName[2]), XtRString, "White"},
  115.   {XtNfaceColor3, XtCLabel, XtRString, sizeof(String),
  116.    XtOffset(RubikWidget, rubik.faceName[3]), XtRString, "Green"},
  117.   {XtNfaceColor4, XtCLabel, XtRString, sizeof(String),
  118.    XtOffset(RubikWidget, rubik.faceName[4]), XtRString, "Orange"},
  119.   {XtNfaceColor5, XtCLabel, XtRString, sizeof(String),
  120.    XtOffset(RubikWidget, rubik.faceName[5]), XtRString, "Blue"},
  121.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  122.    XtOffset(RubikWidget, rubik.foreground), XtRString, XtDefaultForeground},
  123.   {XtNpieceBorder, XtCColor, XtRPixel, sizeof(Pixel),
  124.    XtOffset(RubikWidget, rubik.borderColor), XtRString, XtDefaultForeground},
  125.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  126.    XtOffset(RubikWidget, core.width), XtRString, "300"},
  127.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  128.    XtOffset(RubikWidget, core.height), XtRString, "400"},
  129.   {XtNsize, XtCSize, XtRInt, sizeof(int),
  130.    XtOffset(RubikWidget, rubik.size), XtRString, "3"}, /* DEFAULTCUBES */
  131.   {XtNorient, XtCOrient, XtRBoolean, sizeof(Boolean),
  132.    XtOffset(RubikWidget, rubik.orient), XtRString, "FALSE"}, /* DEFAULTORIENT */
  133.   {XtNmono, XtCMono, XtRBoolean, sizeof(Boolean),
  134.    XtOffset(RubikWidget, rubik.mono), XtRString, "FALSE"},
  135.   {XtNface, XtCFace, XtRInt, sizeof(int),
  136.    XtOffset(RubikWidget, rubik.currentFace), XtRString, "-1"},
  137.   {XtNpos, XtCPos, XtRInt, sizeof(int),
  138.    XtOffset(RubikWidget, rubik.currentPosition), XtRString, "-1"},
  139.   {XtNdirection, XtCDirection, XtRInt, sizeof(int),
  140.    XtOffset(RubikWidget, rubik.currentDirection), XtRString, "-1"},
  141.   {XtNpractice, XtCBoolean, XtRBoolean, sizeof(Boolean),
  142.    XtOffset(RubikWidget, rubik.practice), XtRString, "FALSE"},
  143.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  144.    XtOffset(RubikWidget, rubik.started), XtRString, "FALSE"},
  145.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  146.    XtOffset(RubikWidget, rubik.select), XtRCallback, NULL}
  147. };
  148.  
  149. Rubik2DClassRec rubik2dClassRec =
  150. {
  151.   {
  152.     (WidgetClass) &rubikClassRec,    /* superclass */
  153.     "Rubik2D",                /* class name */
  154.     sizeof(Rubik2DRec),            /* widget size */
  155.     NULL,                /* class initialize */
  156.     NULL,                /* class part initialize */
  157.     FALSE,                /* class inited */
  158.     InitializeRubik2D,            /* initialize */
  159.     NULL,                /* initialize hook */
  160.     XtInheritRealize,            /* realize */
  161.     actionsListRubik2D,            /* actions */
  162.     XtNumber(actionsListRubik2D),    /* num actions */
  163.     resourcesRubik2D,            /* resources */
  164.     XtNumber(resourcesRubik2D),        /* num resources */
  165.     NULLQUARK,                /* xrm class */
  166.     TRUE,                /* compress motion */
  167.     TRUE,                /* compress exposure */
  168.     TRUE,                /* compress enterleave */
  169.     TRUE,                /* visible interest */
  170.     NULL,                /* destroy */
  171.     ResizeRubik2D,            /* resize */
  172.     ExposeRubik2D,            /* expose */
  173.     SetValuesRubik2D,            /* set values */
  174.     NULL,                /* set values hook */
  175.     XtInheritSetValuesAlmost,        /* set values almost */
  176.     NULL,                /* get values hook */
  177.     XtInheritAcceptFocus,        /* accept focus */
  178.     XtVersion,                /* version */
  179.     NULL,                /* callback private */
  180.     defaultTranslationsRubik2D,        /* tm table */
  181.     NULL,                /* query geometry */
  182.     NULL,                /* display accelerator */
  183.     NULL                /* extension */
  184.   },
  185.   {
  186.     0                    /* ignore */
  187.   },
  188.   {
  189.     0                    /* ignore */
  190.   }
  191. };
  192.  
  193. WidgetClass rubik2dWidgetClass = (WidgetClass) &rubik2dClassRec;
  194.  
  195. static RowNext rotateToRow[MAXFACES] = /*CW to min face*/
  196. {
  197.   {1,   LEFT,    TOP},
  198.   {0, BOTTOM,  RIGHT},
  199.   {0,  RIGHT, BOTTOM},
  200.   {0,    TOP,   LEFT},
  201.   {1,  RIGHT, BOTTOM},
  202.   {0,   LEFT,    TOP}
  203. };
  204. static int planeToCube[MAXRECT] = {6, 0, 6, 1, 2, 3, 6, 4, 6, 6, 5, 6};
  205. static int cubeToPlane[MAXFACES] = {1, 3, 4, 5, 7, 10};
  206.  
  207. static void InitializeRubik2D(request, new)
  208.   Widget request, new;
  209. {
  210.   Rubik2DWidget w = (Rubik2DWidget) new;
  211.  
  212.   w->rubik.dim = 2;
  213.   ResizeRubik2D(w);
  214. }
  215.  
  216. static void ResizeRubik2D(w)
  217.   Rubik2DWidget w;
  218. {
  219.   int tempLength;
  220.  
  221.   w->rubik.delta = 3;
  222.   w->rubik.vertical = (w->core.height >= w->core.width);
  223.   if (w->rubik.vertical)
  224.     tempLength = MIN(w->core.height / MAXY, w->core.width / MAXX);
  225.   else
  226.     tempLength = MIN(w->core.height / MAXX, w->core.width / MAXY);
  227.   w->rubik2d.cubeLength = MAX((tempLength - w->rubik.delta - 1) /
  228.      w->rubik.size, 0);
  229.   w->rubik2d.faceLength = w->rubik.size * w->rubik2d.cubeLength;
  230.   w->rubik2d.viewLength = w->rubik2d.faceLength + w->rubik.delta;
  231.   if (w->rubik.vertical) {
  232.     w->rubik.puzzleSize.x = MAXX * (w->rubik2d.viewLength - 1) +
  233.       w->rubik.delta;
  234.     w->rubik.puzzleSize.y = MAXY * (w->rubik2d.viewLength - 1) +
  235.       w->rubik.delta;
  236.   } else {
  237.     w->rubik.puzzleSize.x = MAXY * (w->rubik2d.viewLength - 1) +
  238.       w->rubik.delta;
  239.     w->rubik.puzzleSize.y = MAXX * (w->rubik2d.viewLength - 1) +
  240.       w->rubik.delta;
  241.   }
  242.   w->rubik.puzzleOffset.x = ((int) w->core.width - w->rubik.puzzleSize.x)
  243.     / 2;
  244.   w->rubik.puzzleOffset.y = ((int) w->core.height - w->rubik.puzzleSize.y)
  245.     / 2;
  246.   ResizePolyhedrons(w);
  247. }
  248.  
  249. static void ExposeRubik2D(new, event, region)
  250.   Widget new;
  251.   XEvent *event;
  252.   Region region; /* Not used */
  253. {
  254.   Rubik2DWidget w = (Rubik2DWidget) new;
  255.  
  256.   if (w->core.visible) {
  257.     DrawFrame(w, w->rubik.puzzleGC);
  258.     DrawAllPolyhedrons((RubikWidget) w);
  259.   }
  260. }
  261.  
  262. static Boolean SetValuesRubik2D(current, request, new)
  263.   Widget current, request, new;
  264. {
  265.   Rubik2DWidget c = (Rubik2DWidget) current, w = (Rubik2DWidget) new;
  266.   Boolean redraw = FALSE;
  267.  
  268.   if (w->rubik.size != c->rubik.size) {
  269.     ResetPolyhedrons((RubikWidget) w);
  270.     ResizeRubik2D(w);
  271.     redraw = TRUE;
  272.   }
  273.   if (w->rubik2d.cubeLength != c->rubik2d.cubeLength) {
  274.     ResizeRubik2D(w);
  275.     redraw = TRUE;
  276.   }
  277.   return (redraw);
  278. }
  279.  
  280. static void MoveRubik2DTop(w, event, args, nArgs)
  281.   Rubik2DWidget w;
  282.   XEvent *event;
  283.   char *args[];
  284.   int nArgs;
  285. {
  286.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TOP,
  287.     (int) (event->xkey.state & ControlMask));
  288. }
  289.  
  290. static void MoveRubik2DLeft(w, event, args, nArgs)
  291.   Rubik2DWidget w;
  292.   XEvent *event;
  293.   char *args[];
  294.   int nArgs;
  295. {
  296.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, LEFT,
  297.     (int) (event->xkey.state & ControlMask));
  298. }
  299.  
  300. static void MoveRubik2DRight(w, event, args, nArgs)
  301.   Rubik2DWidget w;
  302.   XEvent *event;
  303.   char *args[];
  304.   int nArgs;
  305. {
  306.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, RIGHT,
  307.     (int) (event->xkey.state & ControlMask));
  308. }
  309.  
  310. static void MoveRubik2DBottom(w, event, args, nArgs)
  311.   Rubik2DWidget w;
  312.   XEvent *event;
  313.   char *args[];
  314.   int nArgs;
  315. {
  316.   MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BOTTOM,
  317.     (int) (event->xkey.state & ControlMask));
  318. }
  319.  
  320. static void ResizePolyhedrons(w)
  321.   Rubik2DWidget w;
  322. {
  323.   w->rubik2d.cubeLength = MAX(w->rubik2d.faceLength /
  324.     w->rubik.size - w->rubik.delta + 1, 0);
  325.   w->rubik.orientLineLength = w->rubik2d.cubeLength / 4;
  326.   w->rubik.letterOffset.x = -2;
  327.   w->rubik.letterOffset.y = 4;
  328. }
  329.  
  330. int SelectPolyhedrons2D(w, x, y, face, position)
  331.   Rubik2DWidget w;
  332.   int x, y;
  333.   int *face;
  334.   int *position;
  335. {
  336.   int faceX, faceY, i, j;
  337.  
  338.   x -= w->rubik.puzzleOffset.x;
  339.   y -= w->rubik.puzzleOffset.y;
  340.   faceX = x / w->rubik2d.viewLength;
  341.   faceY = y / w->rubik2d.viewLength;
  342.   i = MAX((x - faceX * w->rubik2d.viewLength - w->rubik.delta)  /
  343.     (w->rubik2d.cubeLength + w->rubik.delta - 1), 0); 
  344.   j = MAX((y - faceY * w->rubik2d.viewLength - w->rubik.delta)  /
  345.      (w->rubik2d.cubeLength + w->rubik.delta - 1), 0);
  346.   if ((faceX != 1 && faceY != 1) || 
  347.       (faceX >= 3 && w->rubik.vertical) ||
  348.       (faceY >= 3 && !w->rubik.vertical))
  349.     return FALSE;
  350.   if (i >= w->rubik.size)
  351.     i = w->rubik.size - 1;
  352.   if (j >= w->rubik.size)
  353.     j = w->rubik.size - 1;
  354.   *face = planeToCube[faceX + faceY * MAXX];
  355.   if (faceX == 3) {
  356.     *face = MAXFACES - 1;
  357.     i = w->rubik.size - 1 - i;
  358.     j = w->rubik.size - 1 - j;
  359.   }
  360.   *position = j * w->rubik.size + i;
  361.   return TRUE;
  362. }
  363.  
  364. int NarrowSelection2D(w, face, position, direction)
  365.   Rubik2DWidget w;
  366.   int *face;
  367.   int *position;
  368.   int *direction;
  369. {
  370.   int i, j;
  371.  
  372.   if (*face == MAXFACES - 1 && *direction < MAXORIENT && !w->rubik.vertical)
  373.     *direction = (*direction + HALF) % MAXORIENT;
  374.   /* Remap to row movement */
  375.   if (*direction == CW || *direction == CCW) {
  376.     *direction = (*direction == CCW) ?
  377.       (rotateToRow[*face].direction + 2) % MAXORIENT :
  378.       rotateToRow[*face].direction;
  379.     i = j = (rotateToRow[*face].sideFace == LEFT ||
  380.              rotateToRow[*face].sideFace == BOTTOM) ? w->rubik.size - 1 : 0;
  381.     *face = rotateToRow[*face].face;
  382.     *position = j * w->rubik.size + i;
  383.   }
  384.   return TRUE;
  385. }
  386.  
  387. static void DrawFrame(w, gc)
  388.   Rubik2DWidget w;
  389.   GC gc;
  390. {
  391.   int i;
  392.   XPoint pos[MAXXY + 1], letters;
  393.   
  394.   for (i = 0; i <= MAXXY; i++) {
  395.     pos[i].x = i * w->rubik2d.viewLength + w->rubik.puzzleOffset.x;
  396.     pos[i].y = i * w->rubik2d.viewLength + w->rubik.puzzleOffset.y;
  397.   }
  398.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  399.     pos[1].x, pos[0].y, pos[2].x, pos[0].y);
  400.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  401.     pos[3].x, pos[1].y, pos[3].x, pos[2].y);
  402.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  403.     pos[1].x, pos[3].y, pos[2].x, pos[3].y);
  404.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  405.     pos[0].x, pos[1].y, pos[0].x, pos[2].y);
  406.   letters.x = pos[0].x + w->rubik2d.viewLength / 2 - w->rubik.delta;
  407.   letters.y = pos[0].y + w->rubik2d.viewLength / 2;
  408.   XDrawString(XtDisplay(w), XtWindow(w), gc,
  409.     (int) (letters.x + 5 * w->rubik.letterOffset.x),
  410.     (int) (letters.y + w->rubik.letterOffset.y), "Front", 5);
  411.   letters.x = pos[2].x + w->rubik2d.viewLength / 2 - w->rubik.delta;
  412.   letters.y = pos[2].y + w->rubik2d.viewLength / 2;
  413.   XDrawString(XtDisplay(w), XtWindow(w), gc,
  414.     (int) (letters.x + 4 * w->rubik.letterOffset.x),
  415.     (int) (letters.y + w->rubik.letterOffset.y), "Back", 4);
  416.   if (w->rubik.vertical) {
  417.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  418.       pos[1].x, pos[0].y, pos[1].x, pos[4].y);
  419.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  420.       pos[2].x, pos[0].y, pos[2].x, pos[4].y);
  421.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  422.       pos[0].x, pos[1].y, pos[3].x, pos[1].y);
  423.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  424.       pos[0].x, pos[2].y, pos[3].x, pos[2].y);
  425.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  426.       pos[1].x, pos[4].y, pos[2].x, pos[4].y);
  427.   } else {
  428.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  429.       pos[0].x, pos[1].y, pos[4].x, pos[1].y);
  430.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  431.       pos[0].x, pos[2].y, pos[4].x, pos[2].y);
  432.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  433.       pos[1].x, pos[0].y, pos[1].x, pos[3].y);
  434.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  435.       pos[2].x, pos[0].y, pos[2].x, pos[3].y);
  436.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  437.       pos[4].x, pos[1].y, pos[4].x, pos[2].y);
  438.   }
  439. }   
  440.  
  441. void DrawSquare2D(w, face, position, offset)
  442.   Rubik2DWidget w;
  443.   int face, position, offset;
  444. {
  445.   int dx, dy, orient, i, j;
  446.  
  447.   i = position % w->rubik.size;
  448.   j = position / w->rubik.size;
  449.   orient = w->rubik.cubeLoc[face][position].rotation;
  450.   if (w->rubik.vertical || face != MAXFACES - 1) {
  451.     dx = (cubeToPlane[face] % MAXX) * w->rubik2d.viewLength +
  452.       i * (w->rubik2d.cubeLength + w->rubik.delta - 1);
  453.     dy = (cubeToPlane[face] / MAXX) * w->rubik2d.viewLength +
  454.       j * (w->rubik2d.cubeLength + w->rubik.delta - 1);
  455.   } else {
  456.     dx = (cubeToPlane[face] / MAXX) * w->rubik2d.viewLength +
  457.       (w->rubik.size - 1 - i) * (w->rubik2d.cubeLength + w->rubik.delta -
  458.       1);
  459.     dy = (cubeToPlane[face] % MAXX) * w->rubik2d.viewLength +
  460.       (w->rubik.size - 1 - j) * (w->rubik2d.cubeLength + w->rubik.delta -
  461.       1);
  462.     orient = (orient + HALF) % STRT;
  463.   }
  464.   dx += w->rubik.puzzleOffset.x + w->rubik.delta;
  465.   dy += w->rubik.puzzleOffset.y + w->rubik.delta;
  466.   if (offset) {
  467.     XFillRectangle(XtDisplay(w), XtWindow(w),
  468.       w->rubik.borderGC, dx, dy, w->rubik2d.cubeLength, w->rubik2d.cubeLength);
  469.     XDrawRectangle(XtDisplay(w), XtWindow(w),
  470.       w->rubik.faceGC[w->rubik.cubeLoc[face][position].face],
  471.       dx, dy, w->rubik2d.cubeLength, w->rubik2d.cubeLength);
  472.   } else {
  473.     XFillRectangle(XtDisplay(w), XtWindow(w),
  474.       w->rubik.faceGC[w->rubik.cubeLoc[face][position].face],
  475.       dx, dy, w->rubik2d.cubeLength, w->rubik2d.cubeLength);
  476.     XDrawRectangle(XtDisplay(w), XtWindow(w),
  477.       w->rubik.borderGC, dx, dy, w->rubik2d.cubeLength, w->rubik2d.cubeLength);
  478.   }
  479.   if (w->rubik.depth == 1 || w->rubik.mono) {
  480.     int letterX, letterY;
  481.     char buf[2];
  482.  
  483.     (void) sprintf(buf, "%c",
  484.              w->rubik.faceName[w->rubik.cubeLoc[face][position].face][0]);
  485.     letterX = dx + w->rubik2d.cubeLength / 2 + w->rubik.letterOffset.x;
  486.     letterY = dy + w->rubik2d.cubeLength / 2 + w->rubik.letterOffset.y;
  487.     XDrawString(XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  488.       letterX, letterY, buf, 1);
  489.   }
  490.   if (w->rubik.orient)
  491.     DrawOrientLine(w, orient, dx, dy);
  492. }
  493.  
  494. static void DrawOrientLine(w, orient, dx, dy)
  495.   Rubik2DWidget w;
  496.   int orient, dx, dy;
  497. {
  498.   switch (orient) {
  499.     case TOP:
  500.       XDrawLine (XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  501.                  dx + w->rubik2d.cubeLength / 2,
  502.                  dy,
  503.                  dx + w->rubik2d.cubeLength / 2,
  504.                  dy + w->rubik.orientLineLength);
  505.       return;
  506.     case RIGHT:
  507.       XDrawLine (XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  508.                  dx + w->rubik2d.cubeLength,
  509.                  dy + w->rubik2d.cubeLength / 2,
  510.                  dx + w->rubik2d.cubeLength - w->rubik.orientLineLength -
  511.                    1,
  512.                  dy + w->rubik2d.cubeLength / 2);
  513.       return;
  514.     case BOTTOM:
  515.       XDrawLine (XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  516.                  dx + w->rubik2d.cubeLength / 2,
  517.                  dy + w->rubik2d.cubeLength,
  518.                  dx + w->rubik2d.cubeLength / 2,
  519.                  dy + w->rubik2d.cubeLength - w->rubik.orientLineLength -
  520.                    1);
  521.       return;
  522.     case LEFT:
  523.       XDrawLine (XtDisplay(w), XtWindow(w), w->rubik.inverseGC,
  524.                  dx,
  525.                  dy + w->rubik2d.cubeLength / 2,
  526.                  dx + w->rubik.orientLineLength,
  527.                  dy + w->rubik2d.cubeLength / 2);
  528.       return;
  529.     default:
  530.       (void) printf ("DrawOrientLine: orient %d\n", orient);
  531.   }
  532. }
  533.